package com.wayz.service;

import com.alibaba.fastjson.JSON;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.CreateSymlinkRequest;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.imm.main.IMMClient;
import com.aliyuncs.imm.model.v20170906.ConvertOfficeFormatRequest;
import com.aliyuncs.imm.model.v20170906.ConvertOfficeFormatResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
import com.wayz.constants.CFileStatus;
import com.wayz.constants.CFileType;
import com.wayz.entity.model.DUploadFileCreate;
import com.wayz.entity.model.DUploadFileModify;
import com.wayz.entity.pojo.UploadFileInfo;
import com.wayz.entity.pojo.UploadFileKeyInfo;
import com.wayz.entity.redis.company.RCompany;
import com.wayz.entity.redis.RFunctionVersion;
import com.wayz.entity.redis.RUser;
import com.wayz.exception.WayzException;
import com.wayz.mapper.DUploadFileDAO;
import com.wayz.redis.*;
import com.wayz.util.EncryptHelper;
import org.apache.dubbo.config.annotation.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;

import javax.annotation.Resource;
import java.io.*;

/**
 * 阿里云开放式存储服务实现类
 * 
 * @author yinjy
 *
 */
@Service(version = "1.0.0", protocol = "dubbo")
@RefreshScope
public class AliossServiceImpl implements AliossService {

	/** 标识相关 */
	/** 上传文件标识 */
	@Resource(name = "rUploadFileId")
	private RUploadFileId rUploadFileId = null;

	/** DAO相关 */
	/** 上传文件DAO */
	@Resource(name = "dUploadFileDAO")
	private DUploadFileDAO dUploadFileDAO = null;

	/** 公司对象 */
	@Resource(name = "rCompanyObject")
	private RCompanyObject rCompanyObject = null;

	/** 配置相关 */
	/** 访问标识 */
	@Value("${alioss.accessId}")
	private String accessId = null;
	/** 访问键值 */
	@Value("${alioss.accessKey}")
	private String accessKey = null;
	/** 服务端点 */
	@Value("${alioss.endPoint}")
	private String endPoint = null;
	/** 容器名称 */
	@Value("${alioss.bucketName}")
	private String bucketName = null;
	/** 服访问地址 */
	@Value("${alioss.baseUrl}")
	private String baseUrl = null;
	/** STS名称 */
	@Value("${sts.aliName}")
	private String stsAliName = null;
	/** STSID */
	@Value("${sts.accessId}")
	private String stsAccessId = null;
	/** STSKEY */
	@Value("${sts.accessKey}")
	private String stsAccessKey = null;
	/** STS服务 */
	@Value("${sts.endpoint}")
	private String stsEndpoint = null;
	/** 开发环境 */
	//@Value("${mode}")
	//private String mode = null;
	/** Session名称 */
	@Value("${sts.roleSessionName}")
	private String roleSessionName = null;
	/** Session名称 */
	@Value("${sts.regionId}")
	private String stsRegionId = null;

	/** 用户对象 */
	@Resource(name = "rUserObject")
	private RUserObject rUserObject = null;

	/** redis相关 */
	@Resource(name = "redisUtils")
	private RedisUtils redisUtils;
	@Resource(name = "rFunctionVersionObject")
	private RFunctionVersionObject rFunctionVersionObject;

	/*	*//** Session名称 */
	/*
	 * @Value("${policy}") private String policy = null;
	 */

	/** 日志相关 */
	private static final Logger LOGGER = LoggerFactory.getLogger(AliossServiceImpl.class);

	/**
	 * 上传文件
	 * 
	 * @param myId 客户标识
	 * @param inputStream 输入流
	 * @param fileName 文件名称
	 * @param fileSize 文件大小
	 * @param contentType 内容类型
	 * @param fileType 文件类型(0:其他文件;1:用户头像;2:日记照片)
	 * @return 文件名称
	 * @throws WayzException 社区健身异常
	 * @throws FileNotFoundException
	 */
	@Override
	public UploadFileInfo uploadFile(Long myId, String filePath, String fileName, long fileSize, String contentType,
									 Short fileType) throws WayzException, FileNotFoundException {
		// 初始化
		UploadFileInfo uploadFileInfo = new UploadFileInfo();
		uploadFileInfo.setStatus(CFileStatus.FAILURE.getValue());

		// 生成文件名称
		String suffix = "jpg";
		if (fileName != null) {
			int index = fileName.lastIndexOf(".");
			if (index >= 0) {
				suffix = fileName.substring(index + 1);
			}
		}
		String filelUrl = CFileType.getDirectory(fileType);
		RUser rUser = rUserObject.get(myId);
		if (rUser != null && rUser.getCompanyId() != null) {
			filelUrl = filelUrl + "/" + rUser.getCompanyId().toString();
		}
		filelUrl = filelUrl
				+ "/"
				+ EncryptHelper.toMD5(fileName + "_" + myId + "_" + contentType + "_" + fileType + "_" + Math.random()
						+ "_" + System.currentTimeMillis()) + "." + suffix;

		// 保存消息
		Long fileId = null;
		if (!fileType.equals(CFileType.SNAP_SHOT.getValue())) {
			fileId = rUploadFileId.increment();
			DUploadFileCreate dUploadFileCreate = new DUploadFileCreate();
			dUploadFileCreate.setCustomerId(myId);
			dUploadFileCreate.setStatus(CFileStatus.UPLOADING.getValue());
			dUploadFileCreate.setType(fileType);
			dUploadFileCreate.setName(fileName);
			dUploadFileCreate.setUrl(baseUrl + filelUrl);
			dUploadFileCreate.setSize(fileSize);
			dUploadFileCreate.setCause(null);
			dUploadFileDAO.create(fileId, dUploadFileCreate);
			uploadFileInfo.setFileId(fileId);
			uploadFileInfo.setStatus(CFileStatus.UPLOADING.getValue());
		}
		// 上传文件
		try {
			// 调用接口
			InputStream inputStream = new FileInputStream(filePath);
			String md5Str = uploadFile(inputStream, filelUrl, fileSize, contentType);

			// 修改状态
			if (!fileType.equals(CFileType.SNAP_SHOT.getValue())) {
				DUploadFileModify dUploadFileModify = new DUploadFileModify();
				dUploadFileModify.setId(fileId);
				dUploadFileModify.setStatus(CFileStatus.SUCCESS.getValue());
				dUploadFileModify.setFilemd5(md5Str);
				dUploadFileDAO.modify(dUploadFileModify);
				uploadFileInfo.setFileMd5(md5Str);
			}
		}
		catch (Exception e) {
			// 修改状态
			if (!fileType.equals(CFileType.SNAP_SHOT.getValue())) {
				DUploadFileModify dUploadFileModify = new DUploadFileModify();
				dUploadFileModify.setId(fileId);
				dUploadFileModify.setStatus(CFileStatus.FAILURE.getValue());
				dUploadFileModify.setCause(e.getMessage());
				dUploadFileDAO.modify(dUploadFileModify);
				uploadFileInfo.setStatus(CFileStatus.FAILURE.getValue());

			}
			// 抛出异常
			throw new WayzException(e);
		}
		finally {
			File file = new File(filePath);
			file.delete();
		}
		uploadFileInfo.setStatus(CFileStatus.SUCCESS.getValue());
		uploadFileInfo.setUrl(baseUrl + filelUrl);

		// 返回文件
		return uploadFileInfo;
	}

	/**
	 * 上传文件
	 * 
	 * @param inputStream 输入流
	 * @param fileName 文件名称
	 * @param fileSize 文件大小
	 * @param contentType 文件类型
	 * @throws WayzException 社区健身异常
	 */
	public String uploadFile(InputStream inputStream, String fileName, long fileSize, String contentType)
			throws WayzException {
		// 文件md5验证码
		String md5Str = null;
		// 打印提示信息
		LOGGER.info("开始上传文件(" + fileName + ")...");

		// 创建客户端
		@SuppressWarnings("deprecation")
		OSSClient client = new OSSClient(endPoint, accessId, accessKey);

		// 上传文件内容
		try {
			ObjectMetadata metadata = new ObjectMetadata();
			metadata.setContentLength(fileSize);
			metadata.setContentType(contentType);
			md5Str = client.putObject(bucketName, fileName, inputStream, metadata).getETag();
		}
		catch (Exception e) {
			LOGGER.info("上传文件(" + fileName + ")内容异常.", e);
			throw new WayzException("上传文件内容异常", e);
		}
		finally {
			client.shutdown();
		}

		// 打印提示信息
		LOGGER.info("完成上传文件(" + fileName + ").");

		return md5Str;
	}

	/**
	 * 删除文件
	 * 
	 * @param fileName 文件全路径
	 * @return 是否成功
	 */
	@Override
	public Boolean deleteFile(String fileName) throws WayzException {
		// 创建客户端
		@SuppressWarnings("deprecation")
		OSSClient client = new OSSClient(endPoint, accessId, accessKey);

		// 上传文件内容
		try {

			if (fileName.regionMatches(0, baseUrl, 0, baseUrl.length())) {
				client.deleteObject(bucketName, fileName.substring(baseUrl.length()));
			}
			else {
				client.deleteObject(bucketName, fileName.substring(fileName.lastIndexOf("/material")));
			}
		}
		catch (Exception e) {
			LOGGER.info("删除OSS文件(" + fileName + ")异常.", e);
			return false;
		}
		finally {
			client.shutdown();
		}

		// 打印提示信息
		LOGGER.info("完成删除文件(" + fileName + ").");
		return true;
	}

	/**
	 * 下载文件
	 * 
	 * @param myId 客户标识
	 * @param fileName 文件名称
	 * @throws WayzException 社区健身异常
	 */
	@SuppressWarnings("deprecation")
	@Override
	public void downloadFile(Long myId, String url, String fileName) throws WayzException {
		// 创建OSSClient实例
		OSSClient client = new OSSClient(endPoint, accessId, accessKey);

		// 下载object到文件
		client.getObject(new GetObjectRequest(bucketName, url), new File(fileName));

		// 关闭client
		client.shutdown();
	}

	/**
	 * 调用STS API 获取阿里云临时安全令牌
	 */
	@Override
	public UploadFileKeyInfo getUploadToken(Long companyId, Long fileSize) throws WayzException {
		UploadFileKeyInfo keyInfo = new UploadFileKeyInfo();
		keyInfo.setBucketName(bucketName);
		keyInfo.setEndPoint(stsRegionId);
		// 开发环境不上传至OSS 代码保留
		/*
		 * if (mode.equals(CRunMode.DEVELOP.getValue())) {
		 * keyInfo.setIsUploadOss(false); return keyInfo; }
		 */
		//
		RCompany rCompany;
		if (companyId != null) {
			rCompany = rCompanyObject.get(companyId);
			Long surplusMaterialLimit = rCompany.getSurplusMaterialLimit();
			keyInfo.setMaterialLimit(surplusMaterialLimit);
			// 素材空间余量判断
			if (fileSize > surplusMaterialLimit) {
				throw new WayzException("素材空间余量不足");
			}
			// 查询版本信息 获取单个素材上传大小限制
			Long singleFileLimit = rFunctionVersionObject.getLong(rCompany.getVersionId(),
					RFunctionVersion.SINGLEFILELIMIT);
			keyInfo.setSingleFileLimit(singleFileLimit);
			if (fileSize > singleFileLimit) {
				throw new WayzException("单个文件超出上传限制");
			}
		}

		String policy = null;
		try {
			// endpointName, String regionId, String product, String domain

			DefaultProfile.addEndpoint(stsEndpoint, stsRegionId, "STS", stsEndpoint);
			IClientProfile profile = DefaultProfile.getProfile(stsRegionId, stsAccessId, stsAccessKey);
			DefaultAcsClient client = new DefaultAcsClient(profile);
			// 用profile构造client
			final AssumeRoleRequest request = new AssumeRoleRequest();
			request.setMethod(MethodType.POST);
			request.setRoleArn(stsAliName);
			request.setRoleSessionName(roleSessionName);
			request.setPolicy(policy); // Optional
			request.setDurationSeconds(3600L);
			final AssumeRoleResponse response = client.getAcsResponse(request);
			keyInfo.setExpiration(response.getCredentials().getExpiration());
			keyInfo.setAccessKeyId(response.getCredentials().getAccessKeyId());
			keyInfo.setAccessKeySecret(response.getCredentials().getAccessKeySecret());
			keyInfo.setSecurityToken(response.getCredentials().getSecurityToken());
			keyInfo.setRequestId(response.getRequestId());
			// keyInfo.setIsUploadOss(true);
		}
		catch (Exception e) {
			e.printStackTrace();
			throw new WayzException("获取文件上传账户信息异常:" + e.toString());
		}
		return keyInfo;
	}

	/**
	 * 设置软链接
	 * 
	 * @param targetObject 目标资源
	 * @param symlink 软链接
	 */
	@Override
	public void setSymlink(String targetObject, String symlink) throws WayzException {
		// 截取前綴
		if (targetObject.indexOf(baseUrl) == 0) {
			targetObject = targetObject.substring(baseUrl.length());
		}
		// 创建OSSClient实例。
		OSS ossClient = new OSSClientBuilder().build(endPoint, accessId, accessKey);

		// 创建上传文件元信息。
		ObjectMetadata metadata = ossClient.getObjectMetadata(bucketName, targetObject);

		// 创建CreateSymlinkRequest。
		CreateSymlinkRequest createSymlinkRequest = new CreateSymlinkRequest(bucketName, symlink, targetObject);

		// 设置元信息。
		createSymlinkRequest.setMetadata(metadata);

		// 创建软链接。
		ossClient.createSymlink(createSymlinkRequest);

		// 关闭OSSClient。
		ossClient.shutdown();

	}

	/**
	 * 测试主函数
	 * 
	 * @param args 参数数组
	 * @throws FileNotFoundException 文件找不到异常
	 * @throws WayzException 云歌异常
	 * @throws com.aliyuncs.exceptions.ClientException
	 * @throws ServerException
	 * @throws ClientException
	 */
	public static void main(String[] args) throws FileNotFoundException, WayzException, ClientException,
			ServerException, com.aliyuncs.exceptions.ClientException {

		// 初始化
		// AliossServiceImpl impl = new AliossServiceImpl();

		// 设置参数
		// impl.accessId = "qzPVh2g14VLkrPWC";
		// impl.accessKey = "oimfP3jnfJZ3KTXCwqwGP4dsTOFSTa";
		// impl.endPoint = "http://oss-cn-beijing.aliyuncs.com";
		// impl.bucketName = "ygsd-test";

		// 上传文件
		// String fileName = "d:/Wildlife.wmv";// "E:/1.jpg";
		// File file = new File(fileName);
		// InputStream inputStream = new FileInputStream(file);
		// impl.uploadFile(inputStream, "Wildlife.wmv", file.length(),
		// "video/x-ms-wmv");// "image/jpeg");

		// 下载文件
		// String url =
		// "http://test.yungeshidai.com/planEeffect/22f8aa937d25fc940b970463a3663c12.jpg";
		// String fileName =
		// "E:\\exportDownload\\play-menu\\0C63FC01D82F\\20171121\\material\\855814b8554eeee75df4c877e642aca3.png";
		// impl.downloadFile(1L,
		// "material/855814b8554eeee75df4c877e642aca3.png", fileName);

		// String ak = "WV3J4Y3kerZ0jJcg";
		// String sk = "3syzytHcOCrpSAMIJQhPca2gZOGsNs";
		// String bucketName = "oohlink";
		// String objectKey = "position/1211.docx";
		// URL url = getUrl("imm/previewdoc,copy_1", ak, sk, bucketName,
		// objectKey);
		// System.out.println(url.toString());
		// bucketName = "oohlink";
		// objectKey = "position/aa.xlsx";
		// url = getUrl("imm/previewdoc,copy_2", ak, sk, bucketName, objectKey);
		// System.out.println(url.toString());

		// docConvertDemo();
		// setSymlink("/content/0147E12190B7A4751BF05351A420D945.mp4",
		// "aa.mp4");

		// # 访问标识
		String accessId = "qzPVh2g14VLkrPWC";
		// # 访问键值
		String accessKey = "oimfP3jnfJZ3KTXCwqwGP4dsTOFSTa";
		// # 服务端点
		String endPoint = "http://oss-cn-beijing.aliyuncs.com";
		// # 容器名称
		String bucketName = "oohlink";
		String targetObject = "app/oohlink_1.2.0.7_release_2020-05-29.apk";
		// # 访问路径
		// alioss.baseUrl=http://res.oohlink.com/
		// 创建OSSClient实例。
		OSS ossClient = new OSSClientBuilder().build(endPoint, accessId, accessKey);

		// 创建上传文件元信息。
		ObjectMetadata metadata = ossClient.getObjectMetadata(bucketName, targetObject);

		// ObjectMetadata metadata = new ObjectMetadata();
		// metadata.setContentType("application/vnd.android.package-archive");
		// // "text/plain");
		// // 设置自定义元信息property的值为property-value。
		// metadata.addUserMetadata("property", "apk");

		// 创建CreateSymlinkRequest。
		CreateSymlinkRequest createSymlinkRequest = new CreateSymlinkRequest(bucketName, "aa.apk", targetObject);

		// 设置元信息。
		createSymlinkRequest.setMetadata(metadata);
		// 创建软链接。
		ossClient.createSymlink(createSymlinkRequest);

		// 关闭OSSClient。
		ossClient.shutdown();

	}

	public static void docConvertDemo() throws ClientException, ServerException,
			com.aliyuncs.exceptions.ClientException {
		// 初始化 IMM 客户端
		IMMClient client = new IMMClient("cn-beijing", "WV3J4Y3kerZ0jJcg", "3syzytHcOCrpSAMIJQhPca2gZOGsNs");
		// 项目名称，请确保该项目已经创建
		String projectName = "office";
		ConvertOfficeFormatRequest officeFormatReq = new ConvertOfficeFormatRequest();

		officeFormatReq.setProject(projectName);
		// officeFormatReq.
		// 设置待转换对文件OSS路径
		officeFormatReq.setSrcUri("oss://oohlink/position/HXB9.doc");
		// 设置文件输出格式为 vector
		officeFormatReq.setTgtType("jpg");// "vector");
		// 设置转换后的输出路径
		officeFormatReq.setTgtUri("oss://oohlink/position/jpg/");
		// officeFormatReq.setEndpoint("oss-cn-beijing.aliyuncs.com");

		@SuppressWarnings("unused")
		IAcsClient acsClient = new DefaultAcsClient(DefaultProfile.getProfile("cn-beijing", "WV3J4Y3kerZ0jJcg",
				"3syzytHcOCrpSAMIJQhPca2gZOGsNs"));

		ConvertOfficeFormatResponse res = client.getResponse(officeFormatReq);

		System.out.println(JSON.toJSON(officeFormatReq));
		System.out.println(JSON.toJSON(res));

	}

	@Override
	public void createUploadFileRecord(Long myId, String fileName, long fileSize, Short fileType, String fileMd5,
			String url) throws WayzException {
		// 保存消息
		Long fileId = null;
		if (!fileType.equals(CFileType.SNAP_SHOT.getValue())) {
			fileId = rUploadFileId.increment();
			DUploadFileCreate dUploadFileCreate = new DUploadFileCreate();
			dUploadFileCreate.setCustomerId(myId);
			dUploadFileCreate.setType(fileType);
			dUploadFileCreate.setName(fileName);
			dUploadFileCreate.setUrl(url);
			dUploadFileCreate.setSize(fileSize);
			dUploadFileCreate.setFilemd5(fileMd5);
			dUploadFileCreate.setStatus(CFileStatus.SUCCESS.getValue());
			dUploadFileCreate.setCause(null);
			dUploadFileDAO.create(fileId, dUploadFileCreate);
		}

	}

}
